package com.fivefu.core.hillstone.utils;


import com.alibaba.fastjson.JSON;
import com.fivefu.base.common.utils.str.StrUtils;
import okhttp3.*;
import org.apache.http.client.methods.RequestBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.net.ssl.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author DELL
 */
@Component
public class OkHttpClients {

    private static final Logger logger = LoggerFactory.getLogger(OkHttpClients.class);

    /**
     * 设置请求头
     * @param builder
     * @param headerMap
     */
    public void putRequestHeader(Request.Builder builder,Map<String,String> headerMap){
        if (headerMap != null && headerMap.size() > 0){
            Iterator<String> it = headerMap.keySet().iterator();
            while (it.hasNext()){
                String key = it.next();
                builder.header(key, headerMap.get(key));
            }
        }
    }

    /**
     * get请求
     */
    public String get(String url, Map<String,String> headerMap, Boolean useSSL) {
        return get(url, headerMap, useSSL, null);
    }

    /**
     * get请求
     */
    public String get(String url, Map<String,String> headerMap, Boolean useSSL, Integer successStatusCode) {
        Request.Builder builder = new Request.Builder().url(url).get();
        putRequestHeader(builder, headerMap);
        Request request = builder.build();
        return exec(request, useSSL, successStatusCode);
    }

    /**
     * POST请求json数据
     */
    public String post(String url, String param, Map<String,String> headerMap, Boolean useSSL){
        return post(url, param, headerMap, useSSL, null);
    }

    /**
     * POST请求map数据
     */
    public String post(String url, Map<String, String> paramMap, Map<String,String> headerMap, Boolean useSSL){
        return post(url, paramMap, headerMap, useSSL, null);
    }

    /**
     * POST请求map数据
     */
    public String post(String url, Map<String, String> paramMap, Map<String,String> headerMap, Boolean useSSL, Integer successStatusCode) {
        return post(url, JSON.toJSONString(paramMap), headerMap, useSSL, successStatusCode);
    }

    /**
     * POST请求json数据
     */
    public String post(String url, String param, Map<String,String> headerMap, Boolean useSSL, Integer successStatusCode) {
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), param);
        Request.Builder builder = new Request.Builder().url(url).post(body);
        putRequestHeader(builder, headerMap);
        Request request = builder.build();
        return exec(request, useSSL, successStatusCode);
    }

    /**
     * PUT请求String数据
     */
    public String put(String url, String param, Map<String,String> headerMap, Boolean useSSL){
        return put(url, param, headerMap, useSSL, null);
    }

    /**
     * PUT请求map数据
     */
    public String put(String url, Map<String, String> paramMap, Map<String,String> headerMap, Boolean useSSL){
        return put(url, paramMap, headerMap, useSSL, null);
    }

    /**
     * PUT请求map数据
     */
    public String put(String url, Map<String, String> paramMap, Map<String,String> headerMap, Boolean useSSL, Integer successStatusCode) {
        return put(url, JSON.toJSONString(paramMap), headerMap, useSSL, successStatusCode);
    }

    /**
     * PUT请求String数据
     */
    public String put(String url, String param, Map<String,String> headerMap, Boolean useSSL, Integer successStatusCode){
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), param);
        Request.Builder builder = new Request.Builder().url(url).put(body);
        putRequestHeader(builder, headerMap);
        Request request = builder.build();
        return exec(request, useSSL, successStatusCode);
    }

    /**
     * POST请求map数据
     */
    public String uploadFile(String targetURL, String filePath, InputStream fileInputStream, String fileName) throws IOException {
        String file = filePath.substring(filePath.indexOf("/")+1) + "/" ;
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("file",  file + fileName,
                        RequestBody.create(MediaType.parse("multipart/form-data"), toByteArray(fileInputStream)))
                .build();

        Request request = new Request.Builder()
//                .header("filePath",formatFileUrl(filePath))
//                .url(targetURL)
                .header("filePath","")
                .url(targetURL)
//                .header("filePath",getValueEncoded(filePath))
//                .header("filePath",filePath)
                .post(requestBody)
                .build();
        return exec(request);
    }

    private static String getValueEncoded(String value) {
        if (value == null) return "null";
        String newValue = value.replace("\n", "");
        try {
            for (int i = 0, length = newValue.length(); i < length; i++) {
                char c = newValue.charAt(i);
                if (c <= '\u001f' || c >= '\u007f') {
                    return URLEncoder.encode(newValue, "UTF-8");
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return newValue;
    }

    public String formatFileUrl(String filePath){
        String str = "";
        try {
            String[] arr = filePath.split("/");
            for (int i = 0 , length = arr.length ; i < length ; i ++){
                if (arr[i].contains(":")){
                    str += arr[i];
                }else{
                    if (i != 0){
                        str += "/";
                    }
                    str += URLEncoder.encode(arr[i],"utf-8");
                }
            }

            str = URLEncoder.encode(filePath,"utf-8");
        }catch (Exception e){
            e.printStackTrace();
        }
        return str;
    }

    private String exec(Request request){
        return exec(request, null, null);
    }

    private String exec(Request request, Boolean useSSL){
        return exec(request, useSSL, null);
    }

    private String exec(Request request, Integer successStatusCode){
        return exec(request, null, successStatusCode);
    }

    private String exec(Request request, Boolean useSSL, Integer successStatusCode) {
        OkHttpClient client = null;
        ResponseBody responseBody = null;
        String result = "error";
        try {
            if (useSSL == null){
                useSSL = false;
            }
            if(useSSL){
                HostnameVerifier hv = new HostnameVerifier() {
                    @Override
                    public boolean verify(String s, SSLSession sslSession) {
                        return true;
                    }
                };
                TrustManager[] trustAllCerts = {new TrustAllTrustManager()};
                SSLContext sc = SSLContext.getInstance("SSL");
                SSLSessionContext sslsc = sc.getServerSessionContext();
                sslsc.setSessionTimeout(0);
                sc.init(null, trustAllCerts, null);
                client = new OkHttpClient.Builder().hostnameVerifier(hv)
//                        .sslSocketFactory(sc.getSocketFactory()).build();
                .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.getX509TrustManager())
                .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
                .build();
            }else {
                client = new OkHttpClient();
            }
            client.newBuilder()
                    .connectTimeout(2 * 1000,
                            TimeUnit.MILLISECONDS)
                    .readTimeout(30 * 1000,
                            TimeUnit.MILLISECONDS)
                    .writeTimeout(30 * 1000,
                            TimeUnit.MILLISECONDS);
            Response response = client.newCall(request).execute();
            if (response.isSuccessful() || (successStatusCode != null && successStatusCode.equals(response.code()))) {
                responseBody = response.body();
                if (responseBody != null) {
                    result = responseBody.string();
                }
            } else {
                throw new Exception(response.message());
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (responseBody != null) {
                responseBody.close();
            }
            if (client != null) {
                client.dispatcher().executorService().shutdown(); // 清除并关闭线程池
                client.connectionPool().evictAll(); // 清除并关闭连接池
                if (client.cache() != null) {
                    try {
                        client.cache().close();// 清除cache
                    } catch (IOException e) {
                        logger.error(e.getMessage(), e);
                    }
                }
            }
        }
        return result;
    }

    /***
     * @Description : inputstream转换byte[]
     * [input]
     * @Return : byte[]
     * @Author : DELL
     * @Date : 2020/3/26 14:07
     */
    public static byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toByteArray();
    }
}